import React from 'react';
import ReactDOM from 'react-dom';
/**
 * 组件的生命周期
 * 结论1:当父节点和子节点同时绑定一个事件函数，点击子节点，state只更新一次。
 * 结论2：在react dom-diff在考虑同级对比，不考虑跨级对比移动
 * 当setstate后  state一定会更新，但有可能因为组件shouldComponentUpdate=false没更新渲染，但state一定更新了
 */
/**
 * 第一次点击
 * 1.在vdom=》dom阶段，回先把handleClick绑定到dom.stroe上，并且会事件委托到document.onclick上，此时document.onclick= dispatchEvent
 * 2.当button触发click事件后，先通过浏览器冒泡机制到document上，此时就是触发document.onclick上的dispatchEvent，并且获取到target和type，并且创建合成时间方法
 * 3.将updateQueue.isBatchUpdate = true，再通过模拟时间冒泡去执行之前绑定在dom.stroe的handleClick
 * 4.此时会进入this.setstate,会调用了Updater实例的addState方法，在addState中会把新的state添加到Updater实例的属性pendingStates数组中，进入emitUpdate触发更新，但是由于isBatchUpdate是false，因此会把Updater实例添加到updateQueue.updaters数组中，此时this.setstate执行完毕，也就是handleClick执行完毕
 * 5.继续进入模拟冒泡阶段，向上查找过程中没有onclick方法，那么就把isBatchUpdate设置成false，然后updateQueue.batchUpdate()进行批量更新操作
 * 6.遍历updateQueue.updaters后，调用Updater实例的updateComponent方法
 * 7.获取到pendingStates和classInstance后，进入shouldUpdate()
 * 8.因为classInstance.shouldComponentUpdate是false，因此会把willUpdate = false，不进行组件更新，但是会把实例classInstance的state设置成新的状态
 * 9.此时第一个Updater实例就执行结束了，此时就会把isBatchUpdate再次设置成false，以及updaters数组长度设置0.
 */
/**
 * 第二次点击，依然先进入第一次点击的前7步
 * 1.进入shouldUpdate()后，此时classInstance.shouldComponentUpdate是true，因此willUpdate也是true，接下来执行componentWillUpdate(),然后把实例classInstance的state设置成新的状态，然后进入forceUpdate（）
 * 2.获取到oldRenderVdom，oldDom的父节点，然后将当前新的实例执行render方法获取newRenderVdom，然后将他们传给compareTwoVdom方法执行
 * 3.因为新vdom和老vdom都有存在，而且类型都是div，因此执行updateElement(oldVdom, newVdom)，进行深度的dom-diff并且可以复用dom节点
 * 4.因为oldVdom.type是div因此是string类型，会先找到oldVdom的真实dom，调用updateProps()更新dom的props，更新完毕后如果div有子节点，那么会进入updateChildren方法更新子节点
 * 5.updateChildren方法中先获取新老子节点形成一个数组，然后遍历后一次调用compareTwoVdom方法
 * 6.当compareTwoVdom方法中进行到第二个子节点，也就是ChildCounter类组件时候，因为是类组件，那么会把老的实例classInstance赋值给newVdom.classInstance，然后调用updateClassComponent(oldVdom, newVdom)
 * 7.updateClassComponent方法中，先获取newVdom.classInstance，如果实例classInstance中有componentWillReceiveProps方法就执行，并且传出newVdom的props。执行完毕后在执行实例classInstance上updater.emitUpdate(newVdom.props)
 * 8.此时拿到了newProps值，因为isBatchUpdate是false就执行updateComponent方法，再执行shouldUpdate方法，在classInstance.props = nextProps，但因为classInstance.shouldComponentUpdate是false，因此不会执行classInstance.forceUpdate()，第二个子节点更新完毕
 * 9.等待第三个子节点button更新完成后，就返回到forceUpdate方法中，将实例的oldRenderVdom = newRenderVdom，然后实例上有如果componentDidUpdate方法，则执行
 * 10.此时第一个Updater实例就执行结束了，此时就会把isBatchUpdate再次设置成false，以及updaters数组长度设置0.
 */
/**
 * 第三次点击和第一次点击一样
 */
/**
 * 第四次点击，前面的5步和第二次点击一样
 * 1.当compareTwoVdom方法中进行到第二个子节点，因此老的有，新的没有，因此会调用unMountVdom(oldVdom);
 * 2.unMountVdom方法中先找到老的dom，然后如果老的vdom的实例上有componentWillUnmount，就执行他，然后将ref.current设置成null，然后递归删除所有子节点，然后通过currentDOM.parentNode.removeChild(currentDOM)删除自己的节点。
 * 3.等待第三个子节点button更新完成后，就返回到forceUpdate方法中，将实例的oldRenderVdom = newRenderVdom，然后实例上有如果componentDidUpdate方法，则执行
 * 4.此时第一个Updater实例就执行结束了，此时就会把isBatchUpdate再次设置成false，以及updaters数组长度设置0.
 */
/**
 * 第五次点击和第一次点击一样
 */

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { number: 0 };
    console.log('Counter 1.constructor');
  }
  componentWillMount() {
    console.log('Counter 2.componentWillMount');
  }
  componentDidMount() {
    console.log('Counter 4.componentDidMount');
  }
  handleClick = () => {
    this.setState({ number: this.state.number + 1 });
  }
  shouldComponentUpdate(nextProps, nextState) {
    console.log('Counter 5.shouldComponentUpdate');
    //奇数不更新，偶数更新 其实不管此方法返回true还是false, this.state其实都会改变 ，如果返回true的话页面会刷新
    return nextState.number % 2 === 0;
  }
  componentWillUpdate() {
    console.log('Counter 6.componentWillUpdate');
  }
  componentDidUpdate() {
    console.log('Counter 7.componentDidUpdate');
  }
  render() {
    console.log('Counter 3.render');
    return (
      <div>
        <p>{this.state.number}</p>
        {
          this.state.number === 4 ? null : <ChildCounter count={this.state.number} />
        }
        <button onClick={this.handleClick}>+</button>
      </div>
    )
  }
}
class ChildCounter extends React.Component {
  componentWillReceiveProps(nextProps) {
    console.log('ChildCounter 4.componentWillReceiveProps');
  }
  componentWillMount() {
    console.log('ChildCounter 1.componentWillMount');
  }
  componentDidMount() {
    console.log('ChildCounter 3.componentDidMount');
  }
  shouldComponentUpdate(nextProps, nextState) {
    console.log('ChildCounter 5.shouldComponentUpdate');
    return nextProps.count % 3 === 0;//只有3的倍数就更新
  }
  componentWillUnmount() {
    
    console.log('ChildCounter 6.componentWillUnmount');
  }
  render() {
    console.log('ChildCounter 2.render');
    return <div>{this.props.count}</div>
  }
}
ReactDOM.render(<Counter />, document.getElementById('root'));

/**
第一次
Counter 1.constructor
Counter 2.componentWillMount
Counter 3.render
ChildCounter 1.componentWillMount
ChildCounter 2.render
ChildCounter 3.componentDidMount
Counter 4.componentDidMount

第1次点击 这个时候 Counter.state.number=1  Counter模2为0才更新，所以不更新
Counter 5.shouldComponentUpdate

第2次点击 这个时候 Counter.state.number=2
Counter 5.shouldComponentUpdate 要
Counter 6.componentWillUpdate
Counter 3.render
ChildCounter 4.componentWillReceiveProps  子组件接收到新的属性
ChildCounter 5.shouldComponentUpdate 子组件只有模3为0才更新，所以不更新。ChildCounter.props.count=2 显示还是0
Counter 7.componentDidUpdate


第3次点击 这个时候 Counter.state.number=3
Counter 5.shouldComponentUpdate

第4次点击 这个时候 Counter.state.number=4
Counter 5.shouldComponentUpdate 要更新
Counter 6.componentWillUpdate 父组件将要更新
Counter 3.render
ChildCounter 6.componentWillUnmount 把子组件销毁掉 子组件被 销毁 卸载
Counter 7.componentDidUpdate

第5次点击 这个时候 Counter.state.number=5 不更新
Counter 5.shouldComponentUpdate

第6次点击
Counter 5.shouldComponentUpdate 父组件要更新
Counter 6.componentWillUpdate 组件将要更新
Counter 3.render
ChildCounter 1.componentWillMount  这个时候子组件需要被 挂载
ChildCounter 2.render
ChildCounter 3.componentDidMount子组件挂载完成
Counter 7.componentDidUpdate 父组件更新完成



 */